
:- compiler_options([xpp_on]).

#define DEBUG_INDEX

#include "char_defs.h"

%% Abolish in case it has been defined
%% ?- abolish(term_expansion/2).


:- dynamic '_$_$_mtindex'/5.	%% For multi-trie indexing
:- dynamic '_$_$_outfile'/2.


:- import parsing_file_name/1 from parse.

:- import
	file_put/2,
	path_sysop/3
   from file_io.
 
:- import
	length/2,
	append/3,
	member/2
   from basics.

%%%% Helper for list manipulation %%%%%%%%
:- import nth0/3, nth1/3, size/2, get_element_index/3, get_nth_element/3 from listProcessing. 
  
:- import concat_atom/2, concat_atom/3 from string.
  
:- import term_variables/2 from constraintLib.
:- import conget/2, conset/2 from gensym.


%%%% debugging %%%%%%%%%%%%%%%%%%%%%
save_result_for_dbg(Result) :-
	open_outfile_if_necessary(Dbg),
	(
	  member(Clause,Result),
	  writeq(Dbg,Clause),
	  file_put(Dbg,CH_DOT),
	  writeln(Dbg:'WRITE'=Clause),
	  nl(Dbg),
	  fail
	;
	  true
	).

open_outfile_if_necessary(FileHandle) :-
	parsing_file_name(File),
	\+ '_$_$_outfile'(File,_), %% if there's no outfile opened 
	!,
	get_out_file_names(File,OutFileName),
	open(OutFileName,write,FileHandle),
	writeln('FILE OPEN':File+OutFileName+FileHandle),
	asserta('_$_$_outfile'(File,FileHandle)).
open_outfile_if_necessary(FileHandle) :-
	parsing_file_name(File),
	'_$_$_outfile'(File,FileHandle).

close_outfile :-
	('_$_$_outfile'(File,FileHandle)
	-> retractall('_$_$_outfile'(File,_)),
	    writeln('FILE CLOSE':FileHandle+File),
	    close(FileHandle)
	;
	    true
	),
	retractall('_$_$_mtindex'(_,_,_,_,_)).
	
%% file names for index and debug
get_out_file_names(File,FileName) :-
	path_sysop(basename,File,Base),
	concat_atom([Base,'_dbg.P'],FileName).


printtrace(Rule) :-
	writeln('CALL:'+Rule),
	Rule,
	writeln('EXIT:'+Rule).

%term_expansion(':-'(Atom(Args)),_) :-
%	writeln(Atom,Args), fail.
	
term_expansion(':-'(mtindex(Functor/Arity,trie,IndexArgOrderSets)),Result) :-
	!,
	length(Args,Arity),
	OriginalHead =.. [Functor|Args],
	get_newbasename(OriginalHead,IndexArgOrderSets,NewBaseName),
	get_mtindexrule(OriginalHead,IndexArgOrderSets,MtindexRule),
	MtindexRule =.. [':-'|[MtindexHead|_]],
	Dispatcher = (OriginalHead :- MtindexHead),
		
	get_indexrules(MtindexHead,IndexArgOrderSets,NewBaseName,IndexRules,IndexRuleHeads),
	asserta('_$_$_mtindex'(Functor,Arity,NewBaseName,IndexArgOrderSets,IndexRuleHeads)),


	get_retractall(IndexRuleHeads,RetractIndexHeads),
	get_retractall(MtindexHead,RetractMtindex),
%	append([RetractMtindex],RetractIndexHeads,ResultRetract),
%	ResultRetract = [(:- retractall(Functor)),RetractMtindex|RetractIndexHeads],
	ResultRetract = [RetractMtindex|RetractIndexHeads],
	
	get_dynamic(MtindexHead,DynamicMtindex),
	get_dynamic(IndexRuleHeads,DynamicIndexHeads),
%	append([DynamicMtindex],DynamicIndexHeads,ResultDynamic),
%	ResultDynamic = [(:- dynamic(Functor/Arity)),DynamicMtindex|DynamicIndexHeads],
	ResultDynamic = [DynamicMtindex|DynamicIndexHeads],
	
	get_table(IndexRuleHeads,TableIndexHeads),
	append(TableIndexHeads,IndexRules,ResultIndex),
	
	%% For debugging
	get_export(MtindexHead,ExportMtindex),
	get_export(IndexRuleHeads,ExportIndexHeads),
%	append([ExportMtindex],ExportIndexHeads,ResultExport),
%	ResultExport = [(:- export(Functor/Arity)),ExportMtindex|ExportIndexHeads],
	ResultExport = [ExportMtindex|ExportIndexHeads],
	
%	DirectiveNewBase = [(:- export(NewBaseName/Arity)),(:- dynamic(NewBaseName/Arity))],
%	append_all([ResultRetract,DirectiveNewBase,ResultExport,ResultDynamic,ResultIndex,[Dispatcher],[MtindexRule]],Result),
	
	append_all([ResultRetract,ResultExport,ResultDynamic,[Dispatcher],[MtindexRule],ResultIndex],Result),
%	append_all([ResultRetract,ResultExport,ResultDynamic,ResultIndex,[Dispatcher],[MtindexRule]],Result),

%	Result = [
%		RetractMtindex,
%		RetractIndexHeads,
%		DynamicMtindex,
%		DynamicIndexHeads,
%		TableIndexHeads,
%		Dispatcher,
%		MtindexRule,
%		IndexRules
%	],

	writeln('RESULT : '=Result),
	save_result_for_dbg(Result).




%%%% term_expansion meets EOF, end of file %%%%
%% If there's a multi-trie indexing, 
%% put Initial indexrule queries for enabling tables.
%% TODO: What if there are more than one multi-trie indexing?
term_expansion(end_of_file,Result) :-
	writeln('EOF!'),
	!,
	%%parsing_file_name(File),
	'_$_$_outfile'(File,_),
	get_out_file_names(File,DbgFile),
	%% TODO : IF the file is not an valid input file (there's no uindex) then do not make idx, or indexed file.
	'_$_$_mtindex'(Functor,Arity,NewBaseName,IndexArgOrderSets,IndexRuleHeads),
	% If: there has been a multi-trie indexing before.
	% Asserts index rule initial query for tabling.
	get_arbitrary_queries(IndexRuleHeads, InitTablingQuery),
	Result = InitTablingQuery, %% [ (?- idx1(_,_)), ... ]
	save_result_for_dbg(Result),
	!,
	writeln('EOF! file closing'),
	close_outfile.
	
	
%%%% Multi-trie indexing target predicates (=Base Facts)
%% term_expansion meets a predicate, p(a,b)
%% Need one more case for facts that match the index.
%% Have to think of an efficient way.
%%%% CAUTION! SHOULD BE IN THE END OF ALL TERM_EXPANSIONS! 
%%%% ESPECIALLY EOF. EOF WILL BE CAUGHT HERE AND NEVER BE BACK. (don't know why)
term_expansion(Hd,Result) :-	
	Hd =.. [Functor|Args],    %% Put head args in Args
	functor(Hd,_,Arity),
	!,
%	fail -> Result = [], !;
	%% If it is a target predicate of multi-trie indexing
	'_$_$_mtindex'(Functor,Arity,NewBaseName,IndexArgOrderSets,IndexRuleHeads),
%%	NewBase =.. [NewBaseHead|Args],
%	get_newbase(Hd,IndexArgNumbers,NewBase),
	get_newbase(NewBaseName, Args, IndexArgOrderSets, NewBase),
%	save_basefacts(NewBase)
	save_result_for_dbg([NewBase]),
	Result = [NewBase].


% Takes care of facts, queries, directives
term_expansion(Hd,Hd) :-
	Hd \= term_expansion(_,_),
	!,
	save_result_for_dbg([Hd]).

	


%%%% Generate Mtindex Rule %%%%%%%%
:- export get_mtindexrule/3.
:- dynamic get_mtindexrule/3.
%% get_mtindexrule(p(X1,X2,X3,X4,X5,X6),[[1,5,6],[2,4],[3]],Result).
%% Result = (p_6_mtindex_156243(X1,X2,X3,X4,X5,X6) :- 
%	nonvar(X1) -> p_6_mtindex_156243_6_index_123(X1,X5,X6,X2,X4,X3)  ';'
%	nonvar(X2) -> p_6_mtindex_156243_6_index_45(X2,X4,X1,X5,X6,X3)  ';'
%	nonvar(X3) -> p_6_mtindex_156243_6_index_6(X3,X1,X5,X6,X2,X4))
get_mtindexrule(OriginalRuleHead,IndexArgOrderSets,Result) :-
	concat_atom(['mtindex_',IndexArgOrderSets],Type),
	new_pred(OriginalRuleHead,Type,MtindexRuleHead),
	OriginalRuleHead =.. [_|Args],
	rearrange_args_list(IndexArgOrderSets,Args,RearrangedArgs),
	rearrange_argnums_list(IndexArgOrderSets,RearrangedIdxArgOrderSets),	
	get_mtindexrule_bodies(MtindexRuleHead,RearrangedIdxArgOrderSets,RearrangedArgs,RuleBody),
	Result = (MtindexRuleHead :- RuleBody).

new_predname(Head,Type,IndexArgNumbers,NewName) :-
	pred_name_args_arity(Head,PredName,_,Arity),
	concat_atom([PredName,'_',Arity,'_',Type,'_',IndexArgNumbers], NewName).

new_pred(OriginalPred,Type,NewPred) :-
	pred_name_args_arity(OriginalPred,OriginalName,Args,Arity),
	concat_atom([OriginalName,'_',Arity,'_',Type], NewName),
	NewPred =.. [NewName|Args].

pred_name_args_arity(Pred,Name,Args,Arity) :-
	Pred =.. [Name|Args],
	functor(Pred,_,Arity).
	
	

%%%% Arrange Order of Arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% rearrange_args_list([[1,5,6],[2,4],[3]], [X1,X2,X3,X4,X5,X6], Result).
%% Result = [X1,X5,X6,X2,X4,X3]
rearrange_args_list(RearrangedIdxArgOrderSets, Args, RearrangedArgs) :- 
	combine_argnums_list(CombinedList, RearrangedIdxArgOrderSets),
	get_args_by_number(CombinedList, Args, RearrangedArgs).

:- dynamic get_args_by_number/3.
:- export get_args_by_number/3.
%% get_args_by_number([1,5,6,2,4,3], [X1,X2,X3,X4,X5,X6], RearrangedArgList).		
get_args_by_number([],_,[]).
get_args_by_number(NumList, Args, RearrangedArgList) :-
	NumList = [Num|T],
	get_args_by_number(T, Args, SubList),
	nth1(Num, Args, Element),
	RearrangedArgList = [Element|SubList].
	
:- export combine_argnums_list/2.
%% combine_argnums_list(CombinedList, [[1,5,6],[2,4],[3]]).
%% combine_argnums_list(CombinedList, [1,2]).
combine_argnums_list([], []).
combine_argnums_list(CombinedList, RearrangedIdxArgOrderSets) :-
	append_all(RearrangedIdxArgOrderSets, CombinedDupList),
	remove_dups(CombinedDupList,CombinedList).

append_all([],[]).
append_all([H|T], Result) :- 
	append_all(T,SubResult),
	append(H,SubResult,Result).

% remove_dups(+List, -NewList):
% New List isbound to List, but with duplicate items removed.
remove_dups([],[]).
remove_dups([First | Rest], NewRest) :-
	member(First, Rest),
	remove_dups(Rest, NewRest).
remove_dups([First | Rest], [First | NewRest]) :-
	not(member(First, Rest)),
	remove_dups(Rest, NewRest).

	




%%%%%%%% Arrange Argument Order Numbers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Reorder 'index numbers' to fit to the order of rearranged args. 
%% ex) [1,5,6], [X1,X2,X3,X4,X5,X6] -> [1,2,3],[X1,X5,X6,X2,X4,X3].
%% rearrange_argnums_list([[1,5,6],[2,4],[3]], RearrangedIdxArgOrderSets). 
%% RearrangedIdxArgOrderSets = [[1,2,3],[4,5],[6]]
rearrange_argnums_list(IndexArgOrderSets, RearrangedIdxArgOrderSets) :-
	%writeln(rearrange_argnums_list(IndexArgOrderSets, RearrangedIdxArgOrderSets)),
	combine_argnums_list(CombinedArgNums, IndexArgOrderSets),
	rearrange_argnums_list_runner(IndexArgOrderSets, CombinedArgNums, RearrangedIdxArgOrderSets).

%% rearrange_argnums_list_runner([[2,4],[3]], [1,5,6,2,4,3], RearrangedIdxArgOrderSets).
%% RearrangedIdxArgOrderSets = [[4,5],[6]].
%% rearrange_argnums_list([[1,5,6],[2,4],[3]],[_h170,_h226,_h240,_h184,_h212,_h198]

rearrange_argnums_list_runner([],_,[]). 	
rearrange_argnums_list_runner(IndexArgOrderSets, CombinedArgNums, [RearrangedArgOrder|SubResult]) :-
	%writeln(rearrange_argnums_list_runner(IndexArgOrderSets, CombinedArgNums, [RearrangedArgOrder|SubResult])),
	IndexArgOrderSets = [IndexArgOrderSetH|T],
	rearrange_argnums(IndexArgOrderSetH,CombinedArgNums,RearrangedArgOrder),	
	rearrange_argnums_list_runner(T, CombinedArgNums, SubResult).

:- dynamic rearrange_argnums/3.
:- export rearrange_argnums/3.
%% rearrange_argnums([2,4], [1,5,6,2,4,3], RearrangedArgOrder).
%% RearrangedArgOrder = [4,5]
%% rearrange_argnums([3], [1,5,6,2,4,3], RearrangedArgOrder).
rearrange_argnums([],_,[]).
rearrange_argnums(ArgOrderSet,CombinedIndexArgOrderSet,RearrangedArgOrder) :-
	%writeln(rearrange_argnums(ArgOrderSet,CombinedIndexArgOrderSet,RearrangedArgOrder)),
	ArgOrderSet = [NumberH|T],
	get_element_index(NumberH,CombinedIndexArgOrderSet,N),
	rearrange_argnums(T, CombinedIndexArgOrderSet, SubResult),
	RearrangedArgOrder = [N|SubResult].


:- export get_mtindexrule_bodies/4.
%% get_mtindexrule_bodies(p_6_mtindex(X1,X2,X3,X4,X5,X6),[[1,2,3],[4,5],[6]],[X1,X5,X6,X2,X4,X3],Result).
%% Result = (nonvar(X1) -> p_6_mtindex_6_index_123(X1,X5,X6,X2,X4,X3)  ';'  
%%			nonvar(X2) -> p_6_mtindex_6_index_45(X2,X4,X1,X5,X6,X3)  ';'  
%%			nonvar(X3) -> p_6_mtindex_6_index_6(X3,X1,X5,X6,X2,X4))
get_mtindexrule_bodies(_,[],_,[]).
get_mtindexrule_bodies(MtindexRuleHead,IndexArgOrderSets,RearrangedArgs,Result) :-
	IndexArgOrderSets = [IndexArgOrderSetH|IndexArgOrderSetT],
	get_indexrule_head(MtindexRuleHead,IndexArgOrderSetH,RearrangedArgs,IndexRuleHead),
	get_nonvar_check(IndexArgOrderSetH, RearrangedArgs, NonVarStatement),
	%%concat_atom([NonVarStatement,'\n',IndexRuleHeadAtom,'\n;\n',SubResult],Result).
	Result1 = (NonVarStatement->IndexRuleHead),
	get_mtindexrule_bodies(MtindexRuleHead,IndexArgOrderSetT,RearrangedArgs,SubResult),
	(SubResult = [] ->
		Result = Result1	%% end of list
	;
		Result = (Result1 ; SubResult)
	).

%%%% INDEX RULES MAIN %%%%%%%%
%%%% Making index rules 
%% based on MtindexHead, List of argument order numbers, Original arguements, 
%% will result index rules and rule heads. 

%:- dynamic get_indexrules/5.
%:- export get_indexrules/5.
% get_indexrule(mtindex(X1,X2,X3,X4,X5,X6), 
%			[[1,5,6],[2,4],[3]], 
%			newbase, 
%			ResultIndexRules, 
%			ResultIndexRuleHeads).	
get_indexrules(MtindexHead, IndexArgOrderSets, NewBaseName, ResultIndexRules, ResultIndexRuleHeads) :-
	MtindexHead =.. [_|Args],
	%% Reorder argument [X1,X2,X3,X4,X5,X6] -> [X1,X5,X6,X2,X4,X3]
	rearrange_args_list(IndexArgOrderSets, Args, RearrangedArgs),

	%% Reorder 'index numbers' to fit to the order of rearranged args. 
	%% ex) [1,5,6], [X1,X2,X3,X4,X5,X6] -> [1,2,3],[X1,X5,X6,X2,X4,X3].
	rearrange_argnums_list(IndexArgOrderSets, RearrangedIdxArgOrderSets), 

	%% Jump into recursive generation of multiple index rules.
	get_indexrules(MtindexHead,RearrangedIdxArgOrderSets,NewBaseName,RearrangedArgs,ResultIndexRules, ResultIndexRuleHeads).
	

%:- export get_indexrules/6.
%% Concatenate index rules in the list (also rule heads too)
%% get_indexrules( mtindex(X1,X2,X3,X4,X5,X6), 
%				[[1,2,3],[4,5],[6]], 
%				newbase, 
%				[X1,X5,X6,X2,X4,X3], 
%				ResultIndexRules, 
%				ResultIndexRuleHeads ).
get_indexrules(_,[],_,_,[],[]).
get_indexrules(MtindexHead,RearrangedIdxArgOrderSets,NewBaseName,RearrangedArgs,ResultIndexRules, ResultIndexRuleHeads) :-
	RearrangedIdxArgOrderSets = [ArgNumSetH|ArgNumSetT],
	get_an_indexrule(MtindexHead,ArgNumSetH,NewBaseName,RearrangedArgs,(IndexRule), IndexRuleHead),
	get_indexrules(MtindexHead,ArgNumSetT,NewBaseName,RearrangedArgs,SubResultRules, SubResultRuleHeads),
	append([IndexRule], SubResultRules, ResultIndexRules),
	append([IndexRuleHead], SubResultRuleHeads, ResultIndexRuleHeads).	
	


%:- export get_an_indexrule/6.
%% get a single index rule and rule head.
%% get_an_indexrule( p(X1,X2,X3,X4,X5,X6),
%			[1,2,3],
%			newbase,
%			[X1,X5,X6,X2,X4,X3], 
%			ResultIndexRule, 
%			ResultIndexRuleHead ).
get_an_indexrule(MtindexHead,IndexArgOrderSet,NewBaseName,RearrangedArgs,ResultIndexRule, ResultIndexRuleHead) :- 
	get_indexrule_head(MtindexHead,IndexArgOrderSet,RearrangedArgs,ResultIndexRuleHead),
	get_indexrule_body(IndexArgOrderSet,NewBaseName,RearrangedArgs,ResultIndexRuleBodyAtom),
	%writeln(['New Rule: ',ResultIndexRuleHead,':-',ResultIndexRuleBodyAtom]),
	ResultIndexRule = (ResultIndexRuleHead :- ResultIndexRuleBodyAtom).



:- dynamic get_indexrule_head/4.
:- export get_indexrule_head/4.
%% get_indexrule_head(p_mtindex(X1,X2,X3,X4,X5,X6),[1,2,3],[X1,X5,X6,X2,X4,X3], ResultIndexRuleHead).
get_indexrule_head(MtindexHead, RearrangedIdxArgOrderSet, RearrangedArgs, ResultIndexRulePred) :- 
	get_idxargs_normargs(0,RearrangedIdxArgOrderSet,RearrangedArgs,ResultIndexArgs,ResultNormArgs),
	new_predname(MtindexHead, 'index', RearrangedIdxArgOrderSet, IndexHeadName), 
	append(ResultIndexArgs,ResultNormArgs,ResultArgs),
	ResultIndexRulePred =.. [IndexHeadName|ResultArgs].	% be careful! this does not result atom but predicate.

:- dynamic get_idxargs_normargs/5.
:- export get_idxargs_normargs/5.
%% get_idxargs_normargs(0,[4,5],[X1,X5,X6,X2,X4,X3],ResultIdxArgs,ResultNormArgs).
%% ResultIndexArgs = [X2,X4]
%% ResultNormArgs = [X1,X5,X6,X3]
get_idxargs_normargs(_,_,[],[],[]) :- !.
get_idxargs_normargs(N,IndexArgOrderSet,InputArgs,ResultIndexArgs,ResultNormArgs) :-
%	[Number|NumberT] = RearrangedIdxArgOrderSet,
	[Arg|ArgT] = InputArgs,
	N1 is N+1,
	!,
	(
		nth0(_,IndexArgOrderSet,N1) ->		% If this arg is for indexing
%			RearrangedIdxArgOrderSet = NumberT,	%  TODO optimization
			get_idxargs_normargs(N1,IndexArgOrderSet,ArgT,SubresultIdxArgs,ResultNormArgs),
			append([Arg],SubresultIdxArgs,ResultIndexArgs)
		;
			get_idxargs_normargs(N1,IndexArgOrderSet,ArgT,ResultIndexArgs,SubresultNormArgs),
			append([Arg],SubresultNormArgs,ResultNormArgs)
	).
	
:- export get_indexrule_head_name/3. 
:- dynamic get_indexrule_head_name/3.
get_indexrule_head_name(MtindexFunctor, IndexArgOrderSet,ResultAuxIndexRuleHeadName) :-
	concat_atom([MtindexFunctor,'_index_',IndexArgOrderSet],ResultAuxIndexRuleHeadName).
%	writeln(['get_idx_rule ResultAuxIndexRuleHeadName',ResultAuxIndexRuleHeadName]).


%% get_nonvar_check([1,2,3],[X1,X5,X6,X2,X4,X3],Result).
:- dynamic get_nonvar_check/3.
:- export get_nonvar_check/3.
get_nonvar_check(ArgOrderSet, Args, Result) :- 
	%writeln(['get_nonvar_check(',ArgOrderSet, Args, Result]),
	ArgOrderSet = [Num|_],
	%writeln(['::calling get_nth_element(',Args, Num, Arg]),
	get_nth_element(Args, Num, Arg),
	Result = nonvar(Arg).

:- dynamic get_indexrule_body/4.
:- export get_indexrule_body/4.
%% Get an index rule body. 
%% Should be provided with a set of arguments order numbers -> [1,5,6]
%% get_indexrule_body([4,5], pb, [X1,X5,X6,X2,X4,X3], Result).
%% Result = (pb(XX1,XX5,XX6,X2,X4,XX3)  ','
%  XX1 = X1  ','
%  XX5 = X5  ','
%  XX6 = X6  ','
%  XX3 = X3)
get_indexrule_body(IndexArgOrderSet,NewBaseName,OriginalArgs,Result) :-
	%writeln(get_indexrule_body(IndexArgOrderSet,NewPredName,OriginalArgs,Result)),
	get_indexrule_newvars(0,IndexArgOrderSet,OriginalArgs,NewArgs),
	NewPred =.. [NewBaseName|NewArgs],	
	get_indexrule_assign_to_newvar(0,IndexArgOrderSet,OriginalArgs,NewArgs,AssignBodyList),
	NewBody = (NewPred,AssignBodyList),
	Result = NewBody.	

%% Get a list of arguments for index rule.
%% Indexed arg use original argument. ex) X2, X4
%% Non-indexed arg is replaced new variable. ex) XX1,XX3,XX5,XX6
%% get_indexrule_newvars(0,[2,4],[X1,X2,X3,X4,X5,X6],Result).
%% Result = [XX1,X2,XX3,X4,XX5,XX6]
get_indexrule_newvars(_,_,[],[]) :- !.
get_indexrule_newvars(N,IndexArgOrderSet,InputArgs,Result) :-
	[Arg|ArgT] = InputArgs,
	N1 is N+1,
	!,
	(
		%% Check whether this argument ('N'th argument) 
		%% is in the arg order set 
		nth0(_,IndexArgOrderSet,N1) ->	
			% If this arg is for indexing
			get_indexrule_newvars(N1,IndexArgOrderSet,ArgT,SubResult),
			%% X2, use original
			append([Arg],SubResult,Result)		
		;
			% else if this argument is non-indexed
			get_indexrule_newvars(N1,IndexArgOrderSet,ArgT,SubResult),
			%% XX1, set a new arg.
			append([_],SubResult,Result)	
	).

%:- dynamic get_indexrule_assign_to_newvar/5.
%:- export get_indexrule_assign_to_newvar/5.

%% Get assigning terms for new vars. 
%% It's a part of index rule body.
%% get_indexrule_assign_to_newvar( 0,	%% N - index cursor of the arg order set
%				[2,4],	%% argument order set
%				[X1,X2,X3,X4,X5,X6],	%% original arguments
%				[XX1,X2,XX3,X4,XX5,XX6], %% mixed new arguments
%				Result ).
%% Result = ( XX1=X1  ','  XX3=X3  ','  XX5=X5  ','  XX6=X6)
get_indexrule_assign_to_newvar(N,IndexArgOrderSet,OriginalArgs,NewArgs,Result) :- 
	OriginalArgs = [OrgArg|OrgArgT],
	NewArgs = [NewArg|NewArgT],
	N1 is N+1,
	!,
	(
	OrgArgT = [] ->
		%% If it is exit condition 
		%% to remove ';' at the end of the result. 
		Result = (NewArg=OrgArg)	
	;	
		%% else, not exit condition,
		(
		%% Check whether this argument ('N'th argument) is 
		%% in the arg order set
		nth0(_,IndexArgOrderSet,N1) ->	
			% If this arg is for indexing
			get_indexrule_assign_to_newvar(N1,IndexArgOrderSet,OrgArgT,NewArgT,SubResult),
			%% Do not put assignment (do nothing)
			Result = SubResult			
		;
			%% This arg is not indexed argument 
			%% - need an assignment for tabling
			get_indexrule_assign_to_newvar(N1,IndexArgOrderSet,OrgArgT,NewArgT,SubResult),
			%% Put assignment XX1=X1
			Result = ( (NewArg=OrgArg) , SubResult)	
		)
	).


	

:- dynamic get_newbase/3, get_newbase/4, get_newbasename/3.
:- export get_newbase/3, get_newbase/4, get_newbasename/3.



%%%%%% CONVERT TO NEW BASE FACT %%%%%%%%%%%%%%%%%%%%%%%%%%% 

%% get_newbase(p(a,b,c,d,e,f),[[1,5,6],[2,4],[3]],NewBase),
%% NewBase = p_6_newbase_156243(a,e,f,b,d,c)
get_newbase(OriginalBase, IndexArgNumbers, NewBase) :-
	OriginalBase =.. [BaseName|Args],
	functor(OriginalBase,_,Arity),
	(
	\+'_$_$_mtindex'(Functor,Arity,NewBaseName,IndexArgOrderSets,IndexRuleHeads) ->
		get_newbasename(OriginalHead,IndexArgNumbers,NewBaseName)
	),
	get_newbase(NewBaseName, Args, IndexArgNumbers, NewBase).
	
get_newbase(NewBaseName, Args, IndexArgNumbers, NewBase) :- 
	rearrange_args_list(IndexArgNumbers, Args, RearrangedArgs),
	NewBase =.. [NewBaseName|RearrangedArgs].


get_newbasename(OriginalHead,IndexArgNumbers,Result) :-
	functor(OriginalHead,Functor,Arity),
	concat_atom([Functor,'_',Arity,'_newbase_',IndexArgNumbers],Result).





%%%%%%%% UTILS %%%%%%%%


get_export([],[]).
get_export(RuleHeads,Result) :-
	RuleHeads = [RuleHead|T],
	functor(RuleHead,RuleName,Arity),
	get_export(T,SubResult),
	Result = [(:- export RuleName/Arity)|SubResult].
get_export(RuleHead,Result) :-
	functor(RuleHead,RuleName,Arity),
	Result = (:- export RuleName/Arity).

%:- export get_dynamic/2.
%:- dynamic get_dynamic/2.
%% get_dynamic(
%		[ p_6_mtindex_156243_index_123(X1,X5,X6,X2,X4,X3),
%		  p_6_mtindex_156243_index_45(X2,X4,X1,X5,X6,X3),
%		  p_6_mtindex_156243_index_6(X3,X1,X5,X6,X2,X4) ],
%		Result).
%% Result = [(:- dynamic p_6_mtindex_156243_index_123/6, ...]
get_dynamic([],[]).
get_dynamic(IndexRuleHeads,DynamicIndexRuleNames) :-
	IndexRuleHeads = [H|T],
	functor(H,_,Arity),
	H =.. [IndexRuleName|_],
	get_dynamic(T,SubResult),
	DynamicIndexRuleNames = [(:- dynamic IndexRuleName/Arity)|SubResult]. 
get_dynamic(RuleHead,Result) :-
	functor(RuleHead,_,Arity),
	RuleHead =.. [RuleName|_],
	Result = (:- dynamic RuleName/Arity).


%:- export get_table/2.
%:- dynamic get_table/2.
%% get_table(
%		[ p_6_mtindex_156243_index_123(X1,X5,X6,X2,X4,X3),
%		  p_6_mtindex_156243_index_45(X2,X4,X1,X5,X6,X3),
%		  p_6_mtindex_156243_index_6(X3,X1,X5,X6,X2,X4) ],
%		Result).
%% Result = [(:- table p_6_mtindex_156243_index_123/6 as subsumptive), ...]
get_table([],[]).
get_table(IndexRuleHeads,TableIndexRuleHeadNames) :-
	IndexRuleHeads = [H|T],
	functor(H,_,Arity),
	H =.. [IndexRuleName|_],
	get_table(T, SubResult),
	TableIndexRuleHeadNames = [(:- table IndexRuleName/Arity as subsumptive)|SubResult].
get_table(RuleHead,Result) :-
	functor(RuleHead,_,Arity),
	Result = (:- table RuleHead/Arity as subsumptive).
	
%:- export get_retractall/2.
%:- dynamic get_retractall/2.
%% get_retractall(
%		[ p_6_mtindex_156243_index_123(X1,X5,X6,X2,X4,X3),
%		  p_6_mtindex_156243_index_45(X2,X4,X1,X5,X6,X3),
%		  p_6_mtindex_156243_index_6(X3,X1,X5,X6,X2,X4) ],
%		Result).
%% Result = [(:- retractall(p_6_mtindex_156243_index_123)), ...]
get_retractall([],[]).
get_retractall(RuleHeads,Result) :-
	RuleHeads = [H|T],
	H =.. [RuleName|_],
	get_retractall(T, SubResult),
	Result = [(:- retractall(RuleName))|SubResult].
get_retractall(RuleHead,Result) :-
	RuleHead =.. [RuleName|_],
	Result = (:- retractall(RuleName)).
	
	

%:- export get_arbitrary_queries/2.
%:- dynamic get_arbitrary_queries/2.
% get_arbitrary_queries(
%		[ p_6_mtindex_156243_index_123(X1,X5,X6,X2,X4,X3),
%		  p_6_mtindex_156243_index_45(X2,X4,X1,X5,X6,X3),
%		  p_6_mtindex_156243_index_6(X3,X1,X5,X6,X2,X4) ],
%		Result).
%% Result = [(?- p_6_mtindex_156243_index_123(_,_,_,_,_,_)), ...]
get_arbitrary_queries([],[]).
get_arbitrary_queries(IndexRuleHeads,IndexInitialQueryForTabling) :-
	IndexRuleHeads = [H|T],
	functor(H,_,Arity),
	H =.. [IndexRuleName|_],
	length(ArbitraryArgs,Arity),
	Query =.. [IndexRuleName|ArbitraryArgs],
	get_arbitrary_queries(T, SubResult),
	IndexInitialQueryForTabling = [(?- Query)|SubResult].
	
	
%% TODO : General get directive util - NOT WORKING.
%% PROBLEM : result consists of not directives but strings.
	
%:- export get_directives/3.
%:- dynamic get_directives/3.
%% get_directives([ p_6_mtindex_156243_index_123(X1,X5,X6,X2,X4,X3),
%%		p_6_mtindex_156243_index_45(X2,X4,X1,X5,X6,X3),
%%		p_6_mtindex_156243_index_6(X3,X1,X5,X6,X2,X4) ],
%%		dynamic,
%%		Result ).
%% Result = [(:-dynamic p_6_mtindex_156243_index_123 / 6),
%%	(:-dynamic p_6_mtindex_156243_index_45 / 6),
%%	(:-dynamic p_6_mtindex_156243_index_6 / 6)]

%get_directives([],_,[]).
%get_directives(RuleHeads, Directive, Result) :-
%	RuleHeads = [H|T],
%	functor(H,_,Arity),
%	H =.. [RuleName|_],
%	get_directives(T,Directive,SubResult),
%	concat_atom([Directive,' ',RuleName],Result0), %% Directive is converted as string here.
%	Result = [(:- Result0/Arity)|SubResult].
%get_directives(RuleHead, Directive, Result) :-
%	functor(RuleHead,_,Arity),
%	RuleHead =.. [RuleName|_],
%	concat_atom([Directive,' ',RuleName],Result0),
%	Result = (:- Result0/Arity).
